package com.yfqy.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yfqy.admin.conf.Idgenerator.SnowflakeIdGenerator;
import com.yfqy.admin.constant.MyConstants;
import com.yfqy.admin.domain.dto.revenue.AddRevenueRecord;
import com.yfqy.admin.domain.dto.revenue.DailyIncomeDTO;
import com.yfqy.admin.domain.dto.revenue.ModifyRevenueRecord;
import com.yfqy.admin.domain.dto.revenue.PaymentTypeStatsDTO;
import com.yfqy.admin.domain.dto.revenue.RevenueRecordDTO;
import com.yfqy.admin.domain.dto.revenue.RevenueRecordQuery;
import com.yfqy.admin.domain.dto.revenue.RevenueStatisticsDTO;
import com.yfqy.admin.domain.entity.RevenueRecord;
import com.yfqy.admin.enums.ResponseEnum;
import com.yfqy.admin.domain.mapper.RevenueRecordMapper;
import com.yfqy.admin.security.login.LoginUserInfo;
import com.yfqy.admin.service.RevenueRecordService;
import com.yfqy.admin.util.AuthUserContext;
import com.yfqy.admin.domain.vo.common.ResultVO;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class RevenueRecordServiceImpl implements RevenueRecordService {

    private final RevenueRecordMapper revenueRecordMapper;
    private final SnowflakeIdGenerator snowflakeIdGenerator;

    public RevenueRecordServiceImpl(RevenueRecordMapper revenueRecordMapper, SnowflakeIdGenerator snowflakeIdGenerator) {
        this.revenueRecordMapper = revenueRecordMapper;
        this.snowflakeIdGenerator = snowflakeIdGenerator;
    }

    @Override
    public void insertRevenueRecords(List<RevenueRecord> revenueRecords) {
        if (CollUtil.isNotEmpty(revenueRecords)) {
            LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
            Long createdBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
            revenueRecords.forEach(record -> {
                record.setId(snowflakeIdGenerator.nextId());
                record.setCreatedBy(createdBy);
                record.setModifiedBy(createdBy);
            });
            revenueRecordMapper.insertBranch(revenueRecords);
        }
    }

    @Override
    public ResultVO<PageInfo<RevenueRecordDTO>> pageList(RevenueRecordQuery query) {
        PageHelper.startPage(query.getPageIndex(), query.getPageSize());
        List<RevenueRecordDTO> dtos = revenueRecordMapper.selectPageListByConditions(query);
        PageInfo<RevenueRecordDTO> pageInfo = new PageInfo<>(dtos);
        PageHelper.clearPage();
        return ResultVO.data(pageInfo);
    }

    @Override
    public ResultVO<String> addRevenueRecord(AddRevenueRecord addRevenueRecord) {
        RevenueRecord bean = BeanUtil.toBean(addRevenueRecord, RevenueRecord.class);
        RevenueRecord record = revenueRecordMapper.selectByCustomerName(addRevenueRecord.getCustomerName());
        if (Objects.isNull(record)) {
            bean.setTheFirst(MyConstants.BT1);
        } else {
            bean.setTheFirst(MyConstants.BT2);
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long createdBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        bean.setCreatedBy(createdBy);
        bean.setModifiedBy(createdBy);
        bean.setId(snowflakeIdGenerator.nextId());
        revenueRecordMapper.insertSelective(bean);
        return ResultVO.data(bean.getId().toString());
    }

    @Override
    public ResultVO<String> modifyRevenueRecord(ModifyRevenueRecord modifyRevenueRecord) {
        RevenueRecord record = revenueRecordMapper.selectByPrimaryKey(modifyRevenueRecord.getId());
        if (Objects.isNull(record)) {
            return ResultVO.fail(ResponseEnum.REVENUE_IS_INVALID);
        }
        BeanUtil.copyProperties(modifyRevenueRecord, record, CopyOptions.create().setIgnoreNullValue(true));
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long createdBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        record.setModifiedBy(createdBy);
        revenueRecordMapper.updateByPrimaryKeySelective(record);
        return ResultVO.success();
    }

    @Override
    public ResultVO<RevenueStatisticsDTO> revenueStatistics() {
        LocalDate today = LocalDate.now();
        RevenueStatisticsDTO statistics = new RevenueStatisticsDTO();

        // 当日统计
        statistics.setTodayIncome(getIncomeByDate(today));
        statistics.setComparedWithYesterdayIncome(
                statistics.getTodayIncome().subtract(getIncomeByDate(today.minusDays(1)))
        );

        // 本周统计
        LocalDate weekStart = today.with(DayOfWeek.MONDAY);
        LocalDate weekEnd = today.with(DayOfWeek.SUNDAY);
        statistics.setWeeklyIncome(getTotalIncomeBetweenDates(weekStart, weekEnd));

        LocalDate lastWeekStart = weekStart.minusWeeks(1);
        LocalDate lastWeekEnd = weekEnd.minusWeeks(1);
        BigDecimal lastWeekIncome = getTotalIncomeBetweenDates(lastWeekStart, lastWeekEnd);
        statistics.setComparedWithLastWeekIncome(
                statistics.getWeeklyIncome().subtract(lastWeekIncome)
        );

        // 本月统计
        LocalDate monthStart = today.withDayOfMonth(1);
        LocalDate monthEnd = today.withDayOfMonth(today.lengthOfMonth());
        statistics.setMonthlyIncome(getTotalIncomeBetweenDates(monthStart, monthEnd));

        LocalDate lastMonthStart = monthStart.minusMonths(1);
        LocalDate lastMonthEnd = lastMonthStart.withDayOfMonth(lastMonthStart.lengthOfMonth());
        BigDecimal lastMonthIncome = getTotalIncomeBetweenDates(lastMonthStart, lastMonthEnd);
        statistics.setComparedWithLastMonthIncome(
                statistics.getMonthlyIncome().subtract(lastMonthIncome)
        );

        // 年度统计
        LocalDate yearStart = today.withDayOfYear(1);
        LocalDate yearEnd = today.withDayOfYear(today.lengthOfYear());
        statistics.setYearlyIncome(getTotalIncomeBetweenDates(yearStart, yearEnd));

        LocalDate lastYearStart = yearStart.minusYears(1);
        LocalDate lastYearEnd = lastYearStart.withDayOfYear(lastYearStart.lengthOfYear());
        BigDecimal lastYearIncome = getTotalIncomeBetweenDates(lastYearStart, lastYearEnd);
        statistics.setComparedWithLastYearIncome(
                statistics.getYearlyIncome().subtract(lastYearIncome)
        );

        return ResultVO.data(statistics);
    }

    private BigDecimal getIncomeByDate(LocalDate date) {
        BigDecimal income = revenueRecordMapper.getIncomeByDate(date);
        return income != null ? income : BigDecimal.ZERO;
    }

    private BigDecimal getTotalIncomeBetweenDates(LocalDate beginDate, LocalDate endDate) {
        BigDecimal income = revenueRecordMapper.getTotalIncomeBetweenDates(beginDate, endDate);
        return income != null ? income : BigDecimal.ZERO;
    }


    public List<DailyIncomeDTO> getLastNDaysIncome(int days) {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1);

        List<DailyIncomeDTO> dailyIncomes = revenueRecordMapper.getDailyIncomeBetweenDates(startDate, endDate);

        // 确保返回所有日期，即使某天没有收入记录
        Map<LocalDate, BigDecimal> incomeMap = dailyIncomes.stream()
                .collect(Collectors.toMap(DailyIncomeDTO::getDate, DailyIncomeDTO::getIncome));

        return startDate.datesUntil(endDate.plusDays(1))
                .map(date -> new DailyIncomeDTO(
                        date,
                        incomeMap.getOrDefault(date, BigDecimal.ZERO)
                ))
                .collect(Collectors.toList());
    }

    // 获取过去30天优化后的支付类型统计
    @Override
    public List<PaymentTypeStatsDTO> getLast30DaysPaymentStats() {
        return revenueRecordMapper.getOptimizedPaymentTypeStatsLast30Days();
    }

    // 获取动态日期范围的优化统计
    @Override
    public List<PaymentTypeStatsDTO> getPaymentStatsByDateRange(Date startDate, Date endDate) {
        return revenueRecordMapper.getOptimizedPaymentTypeStatsByDateRange(startDate, endDate);
    }

    // 带缓存的版本
    @Override
    @Cacheable(value = "paymentStats", key = "#startDate.time + '-' + #endDate.time")
    public List<PaymentTypeStatsDTO> getCachedPaymentStats(Date startDate, Date endDate) {
        return getPaymentStatsByDateRange(startDate, endDate);
    }
}
